package demo.com.thread.service;

import cn.hutool.core.io.resource.ResourceUtil;
import demo.com.thread.dto.DrawDataDTO;
import demo.com.thread.dto.DrawSubDataDTO;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * 维修海报绘制工具
 * @author lin2.zhang
 * @date 2024/10/14
 */
@Slf4j
public class DrawMaintenancePosterTool {
    static String BgUp = "assets/bg-up.png";
    static String BgMid = "assets/bg-mid.png";
    static String BgBottom = "assets/bg-bottom.png";
    static String IcoCompany = "assets/ico-company.png";
    static String IcoUser = "assets/ico-user.png";
    static String ContentTop = "assets/content-top.png";
    static String ContentMid = "assets/content-mid.png";
    static String ContentBottom = "assets/content-bottom.png";

    // 大图高度
    static int bigImgHeight = 473;
    static int bigImgWidth = 630;
    // 小图高度
    static int minImgHeight = 226;
    static int minImgWidth = 303;
    static int min2Distance = 387;
    // 图片间隔高度
    static int imgMidHeight = 20;
    static int imgDistance = 60;
    // 图片宽度
    static int posterWidth = 750;
    static String FONT = "思源黑体";

    public static void main(String[] args) {
        DrawDataDTO drawDataDTO = new DrawDataDTO();
        drawDataDTO.setServiceConsultant("路人甲");
        drawDataDTO.setCompany("中升雷克萨斯公司");
        drawDataDTO.setCarNumber("辽B 12345");
        drawDataDTO.setMileage("999999");
        drawDataDTO.setModel("RX270");
        List<DrawSubDataDTO> subData = new ArrayList<>();
        DrawSubDataDTO sub = new DrawSubDataDTO();
        sub.setName("空调清洗");
        sub.setDescribe("维护");
        subData.add(sub);
        sub = new DrawSubDataDTO();
        sub.setName("清洗前后刹车分泵");
        sub.setDescribe("维护");
        subData.add(sub);
        sub = new DrawSubDataDTO();
        sub.setName("干冰清洗积碳");
        sub.setDescribe("维护火花塞建议一起更换");
        subData.add(sub);
        sub = new DrawSubDataDTO();
        sub.setName("更换空气格空调格");
        sub.setDescribe("脏堵");
        ArrayList<String> contentImg = new ArrayList<>();
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图1.png");
        sub.setContentImg(contentImg);
        subData.add(sub);
        sub = new DrawSubDataDTO();
        sub.setName("更换尾门撑杆");
        sub.setDescribe("无力");
        contentImg = new ArrayList<>();
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图2.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-1.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-2.png");
        sub.setContentImg(contentImg);
        subData.add(sub);
        sub = new DrawSubDataDTO();
        sub.setName("更换发动机皮带");
        sub.setDescribe("老化开裂");
        contentImg = new ArrayList<>();
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图3.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-1.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-2.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-3.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-4.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-4.png");
        sub.setContentImg(contentImg);
        subData.add(sub);
        sub = new DrawSubDataDTO();
        sub.setName("更换轮胎");
        sub.setDescribe("前极限 后老化 左侧轮胎扎钉");
        contentImg = new ArrayList<>();
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-1.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-2.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-3.png");
        contentImg.add("C:\\Users\\Administrator\\Desktop\\中升\\中升\\assets\\图4-4.png");
        sub.setContentImg(contentImg);
        subData.add(sub);

        drawDataDTO.setSubData(subData);
        String outPath = "D:\\temp\\poster.jpg";
        try(OutputStream outputStream = Files.newOutputStream(Paths.get(outPath));) {
            createPoster(drawDataDTO, outputStream);
        } catch (IOException e){
            log.error("海报生成失败", e);
        }
    }


    public static void createPoster(DrawDataDTO drawDataDTO, OutputStream outputStream) {
        int height = 0;
        try {
            // 先绘制各部分最后在进行拼接
            List<BufferedImage> list = new ArrayList<>();
            List<Integer> heights = new ArrayList<>();
            // 绘制头部
            BufferedImage image = drawHead(drawDataDTO.getServiceConsultant(), drawDataDTO.getCompany(),
                    drawDataDTO.getCarNumber(), drawDataDTO.getMileage(), drawDataDTO.getModel());
            list.add(image);
            heights.add(0);
            height = height + image.getHeight();
            // 绘制中间部分
            int midHeight = 0;
            List<DrawSubDataDTO> subData = drawDataDTO.getSubData();
            for (int i = 0; i < subData.size(); i++) {
                DrawSubDataDTO drawSubDataDTO = subData.get(i);
                BufferedImage midPng = assemble(i+1, drawSubDataDTO.getName(), drawSubDataDTO.getDescribe(), drawSubDataDTO.getContentImg());
                list.add(midPng);
                heights.add(height);
                midHeight = midHeight + midPng.getHeight();
                height = height + midPng.getHeight();
            }
            // 绘制底部
            URL resource = ResourceUtil.getResource(BgBottom);
            BufferedImage bgImg = ImageIO.read(resource);
//            // springboot 可以用下面的方法
//            ClassPathResource classPathResource = new ClassPathResource(BgBottom);
//            BufferedImage bgImg = ImageIO.read(classPathResource.getInputStream());
            list.add(bgImg);
            heights.add(height);
            height = height + bgImg.getHeight();
            // 创建一个指定大小的 BufferedImage
            BufferedImage posterImg = new BufferedImage(posterWidth, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = posterImg.createGraphics();
            // 合成图片
            for (int i = 0; i < list.size(); i++) {
                Integer _height = heights.get(i);
                BufferedImage bufferedImage = list.get(i);
                if (i == 1) {
                    URL resource1 = ResourceUtil.getResource(BgMid);
                    BufferedImage backgroundImage = ImageIO.read(resource1);
//                    BufferedImage backgroundImage = ImageIO.read(new ClassPathResource(BgMid).getInputStream());
                    g2d.drawImage(backgroundImage, 0, _height, posterWidth, midHeight, null);
                }
                g2d.drawImage(bufferedImage, 0, _height, null);
            }
            // 释放图形资源
            g2d.dispose();
            // 保存图像为 jpg 文件
            ImageIO.write(posterImg, "jpg", outputStream);
            log.info("车辆诊断报告拼接完成{} 海报保存路径为{}", drawDataDTO.getCarNumber(),outputStream);
        } catch (IOException e) {
            log.error("车辆诊断报告拼接失败", e);
        }
    }

    private static BufferedImage drawHead(String user, String company, String carNumber, String mileage, String model) throws IOException {
        BufferedImage image = ImageIO.read(ResourceUtil.getResource(BgUp));
//        ClassPathResource classPathResource = new ClassPathResource(BgUp);
//        BufferedImage image = ImageIO.read(classPathResource.getInputStream());
        Graphics2D g2d = image.createGraphics();
        Graphics2D g2dFont = image.createGraphics();
        g2d.scale(1.0, 1.0);
        BufferedImage companyPng = ImageIO.read(ResourceUtil.getResource(IcoCompany));
        BufferedImage userPng = ImageIO.read(ResourceUtil.getResource(IcoUser));
//        BufferedImage companyPng = ImageIO.read(new ClassPathResource(IcoCompany).getInputStream());
//        BufferedImage userPng = ImageIO.read(new ClassPathResource(IcoUser).getInputStream());
        g2d.drawImage(companyPng, 40, 287, companyPng.getWidth(), companyPng.getHeight(),null);
        g2d.drawImage(userPng, 40, 327, userPng.getWidth(), userPng.getHeight(), null);
        // 设置抗锯齿模式
        g2dFont.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2dFont.setColor(Color.BLACK);
        g2dFont.setFont(new Font(FONT, Font.PLAIN, 22));
        g2dFont.drawString("经销名称: "+ company, 79, 305);
        g2dFont.drawString("服务顾问: "+ user, 79, 345);
        // 绘制车牌
        g2dFont.setColor(Color.WHITE);
        g2dFont.setFont(new Font(FONT, Font.BOLD, 32));
        g2dFont.drawString(carNumber==null?"":carNumber, 40, 240);
        // 绘制公里数
        g2dFont.setFont(new Font(FONT, Font.PLAIN, 20));
        g2dFont.drawString(mileage==null?"":mileage + "km", 256, 220);
        g2dFont.drawString(model==null?"":model, 256, 250);
        return image;
    }

    private static BufferedImage assemble(int num, String name, String describe, List<String> contentImg) throws IOException {
        // 高度计算
        int fontHeight = 30;
        int fixedHeight = 130;
        Font font = new Font(FONT, Font.PLAIN, 24);
        String[] describes = wrapText(describe, font, 630).split("\n");
        // 计算图片整体占据高度
        int imgSize = contentImg == null ? 0 : contentImg.size();
        int imgHeight;
        if (imgSize <=2) {
            imgHeight = imgSize * (imgMidHeight + bigImgHeight);
        } else if (imgSize%2 == 0) {
            imgHeight = 2*(imgMidHeight + bigImgHeight) + ((imgSize/2)-1)*(imgMidHeight + minImgHeight);
        } else {
            imgHeight = imgMidHeight + bigImgHeight + ((imgSize-1)/2)*(imgMidHeight + minImgHeight);
        }
        // 内容文本高度
        int hc = describes.length * fontHeight;
        int autoHeight = fixedHeight + hc + imgHeight;
        // 生成底图
        BufferedImage image = new BufferedImage(posterWidth, autoHeight, BufferedImage.TYPE_INT_ARGB);

        Graphics2D g2d = image.createGraphics();
        g2d.scale(1.0, 1.0);
        g2d.setColor(new Color(0, 0, 0, 0)); // 设置颜色为透明，这里的四个参数分别是红、绿、蓝、透明度（0 - 255），0表示完全透明
        g2d.fillRect(0, 0, posterWidth, autoHeight);
        BufferedImage contentTopImage = ImageIO.read(ResourceUtil.getResource(ContentTop));
//        BufferedImage contentTopImage = ImageIO.read(new ClassPathResource(ContentTop).getInputStream());
        g2d.drawImage(contentTopImage, 40, 0, contentTopImage.getWidth(), contentTopImage.getHeight(), null);
        // 设置抗锯齿模式
        Graphics2D g2dFont = image.createGraphics();
        g2dFont.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 填补数字
        g2dFont.setColor(Color.WHITE);
        g2dFont.setFont(new Font(FONT, Font.BOLD, 26));
        g2dFont.drawString(String.format("%02d", num), 60, 37);
        g2dFont.drawString(name, 111, 37);
        // 绘制中间的背景
        BufferedImage contentMidImage = ImageIO.read(ResourceUtil.getResource(ContentMid));
//        BufferedImage contentMidImage = ImageIO.read(new ClassPathResource(ContentMid).getInputStream());
        BufferedImage contentBottomImage = ImageIO.read(ResourceUtil.getResource(ContentBottom));
//        BufferedImage contentBottomImage = ImageIO.read(new ClassPathResource(ContentBottom).getInputStream());
        int midHeight = autoHeight - contentTopImage.getHeight() - contentBottomImage.getHeight() - imgMidHeight;
        g2d.drawImage(contentMidImage, 40, contentTopImage.getHeight(), contentMidImage.getWidth(), midHeight, null);
        // 填充内容 动态换行
        g2dFont.setColor(Color.BLACK);
        g2dFont.setFont(font);
        for (int i = 0; i < describes.length; i++) {
            g2dFont.drawString(describes[i], 60, 95 + (fontHeight * i));
        }
        int height = midHeight + contentTopImage.getHeight() - imgHeight;
        // 补充图片
        if (imgSize > 0) {
            if (imgSize <=2) {
                for (int i = 0; i < imgSize; i++) {
                    height = setBig(contentImg.get(i), g2d, height);
                }
            } else if (imgSize%2 == 0) {
                for (int i = 0; i < imgSize; i++) {
                    if (i < 2) {
                        height = setBig(contentImg.get(i), g2d, height);
                    } else {
                        if (i%2 == 0) {
                            height = setSmall(contentImg.get(i),contentImg.get(i+1), g2d, height);
                        }
                    }
                }
            } else {
                for (int i = 0; i < imgSize; i++) {
                    if (i < 1) {
                        height = setBig(contentImg.get(i), g2d, height);
                    } else {
                        if (i%2 == 1) {
                            height = setSmall(contentImg.get(i),contentImg.get(i+1), g2d, height);
                        }
                    }
                }
            }
        }
        // 绘制底部
        g2d.drawImage(contentBottomImage, 40, height, contentBottomImage.getWidth(), contentBottomImage.getHeight(), null);
        // 关闭
        g2d.dispose();
        return image;
    }

    private static int setBig(String url, Graphics2D g2d, int height) throws IOException {
        try {
            BufferedImage fileImg = loadImageFromUrl(url);
            g2d.drawImage(processImage(fileImg, bigImgWidth, bigImgHeight), imgDistance, height, bigImgWidth, bigImgHeight, null);
        } catch (Exception e) {
            log.error("图片合成异常 url{}", url, e);
        }
        height = height + bigImgHeight + imgMidHeight;
        return height;
    }

    private static int setSmall(String urlL, String urlR, Graphics2D g2d, int height) throws IOException {
        try {
            BufferedImage fileImgL = loadImageFromUrl(urlL);
            g2d.drawImage(processImage(fileImgL, minImgWidth, minImgHeight), imgDistance, height, minImgWidth, minImgHeight, null);
        } catch (Exception e) {
            log.error("图片合成异常 url{}", urlL, e);
        }
        try {
            BufferedImage fileImgR = loadImageFromUrl(urlR);
            g2d.drawImage(processImage(fileImgR, minImgWidth, minImgHeight), min2Distance, height, minImgWidth, minImgHeight, null);
        } catch (Exception e) {
            log.error("图片合成异常 url{}", urlR, e);
        }
        height = height + minImgHeight + imgMidHeight;
        return height;
    }

    public static String wrapText(String text, Font font, int maxWidth) {
        BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = img.createGraphics();
        g2d.setFont(font);
        FontMetrics fm = g2d.getFontMetrics();
        StringBuilder wrappedText = new StringBuilder();
        String[] words = text.split("");
        int lineWidth = 0;
        for (String word : words) {
            int wordWidth = fm.stringWidth(word);
            if (lineWidth + wordWidth > maxWidth) {
                wrappedText.append("\n");
                lineWidth = 0;
            }
            wrappedText.append(word);
            lineWidth += wordWidth;
        }
        g2d.dispose();
        return wrappedText.toString();
    }

    public static BufferedImage loadImageFromUrl(String imageUrl) throws IOException {
        if (imageUrl.startsWith("http")) {
            URL url = new URL(imageUrl);
            try (InputStream in = url.openStream()) {
                return ImageIO.read(in);
            }
        } else {
            return ImageIO.read(new File(imageUrl));
        }
    }

    /**
     * 根据传入的图片和长宽，在保持长款比例的前提下对图片从中心进行裁剪。
     * @param originalImage
     * @param maxWidth
     * @param maxHeight
     * @return
     * @throws IOException
     */
    public static BufferedImage processImage(BufferedImage originalImage, int maxWidth, int maxHeight) throws IOException {
        // 读取原始图片
        int originalWidth = originalImage.getWidth();
        int originalHeight = originalImage.getHeight();

        // 计算缩放比例，以保持长宽比不变
        double ratio = Math.max((double) maxWidth / originalWidth, (double) maxHeight / originalHeight);

        // 计算缩放后的尺寸
        int newWidth = (int) (originalWidth * ratio);
        int newHeight = (int) (originalHeight * ratio);

        // 创建一个新的BufferedImage，尺寸为最大宽高，背景透明
        BufferedImage processedImage = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_ARGB);

        // 获取Graphics2D对象用于绘制
        Graphics2D g2d = processedImage.createGraphics();

        // 设置背景透明
        g2d.setComposite(AlphaComposite.Clear);
        g2d.fillRect(0, 0, maxWidth, maxHeight);

        // 设置绘图模式为正常（覆盖模式）
        g2d.setComposite(AlphaComposite.SrcOver);

        // 计算居中绘制的坐标
        int x = (maxWidth - newWidth) / 2;
        int y = (maxHeight - newHeight) / 2;

        // 绘制缩放后的图片到新的BufferedImage上，实现居中显示
        g2d.drawImage(originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), x, y, null);

        g2d.dispose();

        return processedImage;
    }
}
